
#define GL_APP_MAIN
#include "gl_app.h"

#include <GL/glew.h> // [r2]
#include <GL/freeglut.h> // [r1]

extern void appConfigure(GlApp::Configuration& config);
extern void appInitialize(GlApp::AppState& state);
extern void appUpdate(GlApp::AppState& state);
extern void appFinalize(GlApp::AppState& state);
extern void appResize(GlApp::AppState& state, int width, int height);


extern void GlApp::updateAppState(AppState&);


GlApp::AppState g_app;


void idleFunction(void)
{
        glutPostRedisplay();
}

void updateFunction()
{
    GlApp::updateAppState(g_app);

    appUpdate(g_app);

    glutSwapBuffers();
    glutPostRedisplay();
}

void finalizeFunction()
{
    appFinalize(g_app);
}

void initializeFunction()
{
    appInitialize(g_app);
}

void resizeFunction(int width, int height)
{
    g_app.configuration().window().width() = width;
    g_app.configuration().window().height() = height;
    glViewport(0, 0, width, height);
    appResize(g_app, width, height);
}

void initWindow(int argc, char* argv[])
{
        glutInit(&argc, argv);
        glutInitContextVersion(3, 3);
        glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
        glutInitContextProfile(GLUT_CORE_PROFILE);

        glutSetOption(
                GLUT_ACTION_ON_WINDOW_CLOSE,
                GLUT_ACTION_GLUTMAINLOOP_RETURNS
        );
        
        GlApp::Configuration::Window& window(g_app.configuration().window());

        glutInitWindowSize(window.width(), window.height());

        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);

        window.handle() = glutCreateWindow(window.name().c_str());

        if(window.handle() < 1) {
                fprintf(
                        stderr,
                        "ERROR: Could not create a new rendering window.\n"
                );
                exit(EXIT_FAILURE);
        }
        
        glutReshapeFunc(resizeFunction);
        glutDisplayFunc(updateFunction);
        glutIdleFunc(idleFunction);
        glutCloseFunc(finalizeFunction);
}

void initializeGl(int argc, char* argv[])
{
        GLenum GlewInitResult;

        initWindow(argc, argv);

        glewExperimental = GL_TRUE;

        GlewInitResult = glewInit();

        if (GLEW_OK != GlewInitResult) {
                fprintf(
                        stderr,
                        "ERROR: %s\n",
                        glewGetErrorString(GlewInitResult)
                );
                exit(EXIT_FAILURE);
        }

        fprintf(
                stdout,
                "INFO: OpenGL Version: %s\n",
                glGetString(GL_VERSION)
        );

        appInitialize(g_app);
}

int main(int argc, char* argv[])
{
        appConfigure(g_app.configuration());

        initializeGl(argc, argv);

        glutMainLoop();

        exit(EXIT_SUCCESS);
}

